package il.ac.technion.cs236700.address_book;

import il.ac.technion.cs236700.utils.BadData;

import java.util.Map;

/**
 * An address book object maintains contact details with people.
 * 
 * <p>Important: the following is a conceptual description of this interface. 
 * An implementing class may choose 
 * whatever internal representation that fits this description.</p>
 *  
 *  
 * <p>Each contact person (a record) can be thought of as a set of key-value pairs,
 * where both the keys and the values are string.  The set of keys supported 
 * by the address book can be obtained via {@link #getSupportedKeys()}.</p>
 * 
 * <p>The two main services are the {@link #getNormalized()}, 
 * {@link #getConflicts()} methods.</p>
 *  
 * Illegal conditions (illegal keys, ill-formatted input, etc.) - including
 * bad precondition failures - are reported by {@link BadData} exceptions.
 */
public interface AddressBook {
   /**
    * Retrieve all keys supported by this address book. Each key serves 
    * as name of a piece of information that is associated with a 
    * contact person.
    * 
    * <p>In a conforming implementation the set of supported keys should 
    * contain, at least, the following keys:
    * <code> "First Name", "Last Name", "Home Phone", "Mobile Phone",
    * "Work Phone", "Fax", "Email", "Instant Messanger Type",
    * "Instant Messanger ID", "Home Address", "Work Address","Home page",
    * "Title","Company"
    * </code></p> 
    * 
    * @return Array of strings. The returned array is a dedicated copy 
    * that can be mutated by client code.
    */
   public String[] getSupportedKeys();
   
   /**
    * Specify the sequence of keys that will appear in the output 
    * of subsequent calls to {@link #getNormalized()}, 
    * {@link #getConflicts()}, etc.
    * 
    * @param keys Array of keys. Each such key must appear 
    * in {@link #getSupportedKeys()}
    */
   public void setOutput(String... keys);
   
   /**
    * Load a CSV, comma separated value, content into the address book. The 
    * loaded data is added to the existing records (that is: existing data 
    * is not overwritten).
    * 
    * <p>CSV format: The first line is a header line: it is a sequence of 
    * keys where each key must appear on the set of keys defined 
    * by {@link #getSupportedKeys()}.</p>
    * 
    * <p>Each of the following lines is a sequence of strings 
    * describing a single person. Each string in a line 
    * specifies a single detail about that person. The order of the details
    * corresponds to the order of the keys in the header line.</p>
    */
   public void load(String csv);
   
   /**
    * Add a new record to the address book.
    * 
    * @param p Personal details
    * @param home Home address, if null assume all its fields are empty strings
    * @param work Work address, if null assume all its fields are empty strings
    */   
   public void add(Person p, Address home, Address work);

   /**
    * Add a new record to the address book. The key-values pair of 
    * the new record are retrieved from the given map object. 
    * 
    * @param map A map from strings to strings  
    */   
   public void add(Map<String,String> map);
   
   
   /**
    * Obtain all non-conflicting contacts in this address book, consolidate 
    * records pertaining to the same person.
    * 
    * <p>Consolidate-able: Two records can be consolidated if they have the same
    *  first and last name, and they agree on all other keys.
	*  Conflict: Two records are in conflict if they have the same first and
	*  last name, at least one key where where the corresponding values are not
	*  in agreement with each other.
	*  Agreement: Two values (of the same key) "agree" with each other if one of
	*  them is equal to- or is a substring of- the other. An empty string is a 
	*  substring of every string (this definition was not changed </p>
    * 
    * <p>A record in the output cannot be in a conflict with any other record
    * in the output (see {@link #getConflicts())}. Two records are in conflict
    * if they have at least one key where the corresponding values are not in
    * agreement with each other.</p>
    * 
    * <p>The output is a CSV string (same format as in {@link #load(String)}), 
    * where the header line is determined by the last call 
    * to {@link #setOutput(String...)} </p> 
    * 
    * @return A CSV string of contact persons
    */
   public String getNormalized();
   
   
   /**
    * Obtain all conflicting contacts in this address book.
    * Conflict: Two records are in conflict if they have the same first and
	* last name, at least one key where the corresponding values are not
	* in agreement with each other.
	* Agreement: Two values (of the same key) "agree" with each other if one of
	* them is equal to- or is a substring of- the other. An empty string is a 
	* substring of every string (this definition was not changed.
	* </p> Two values  
    * 
    * <p>The set of 
    * keys that is used for determining conflicts is the one defined 
    * by {@link #getSupportedKeys()}.</p> 
    * 
    * <p>The output is a CSV string (same format as in {@link #load(String)}), 
    * where the header line is determined by the last call 
    * to {@link #setOutput(String...)}  </p>
    * 
    * @return A CSV string of conflicting contact persons
    */
   public String getConflicts();
}
